package com.ask.forMe.service.impl;

import com.ask.forMe.model.entity.Rating;
import com.ask.forMe.model.enums.BehaviorType;
import com.ask.forMe.service.RatingUpdateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

@Service
@Slf4j
public class RatingUpdateServiceImpl implements RatingUpdateService {

    private static final double MAX_RATING = 100.0;

    private static final double TIME_DECAY_FACTOR = 0.023;  // 时间衰减因子（30天半衰期）

    /**
     * 购买行为对评分的影响
     *
     * @param rating
     */
    @Override
    public void updateForPurchase(Rating rating) {
        // todo 边际效用递减模型：购买次数越多，增量越小
        double oldRating = rating.getRating();
        double increment = BehaviorType.PURCHASE.getWeight();
        double newRating = Math.min(oldRating + increment, MAX_RATING);
        rating.setRating(newRating);
        log.info("rating of user-item :{}-{}, {}->{}", rating.getUserId(), rating.getItemId(), oldRating, newRating);
    }

    /**
     * 收藏行为对评分的影响
     *
     * @param rating
     */
    @Override
    public void updateForFavorite(Rating rating) {
        double oldRating = rating.getRating();
        double increment = BehaviorType.FAVORITE.getWeight();
        double newRating = Math.min(oldRating + increment, MAX_RATING);
        rating.setRating(newRating);
        log.info("rating of user-item :{}-{}, {}->{}", rating.getUserId(), rating.getItemId(), oldRating, newRating);
    }


    /**
     * 时间衰减函数: 随着时间推移，逐渐降低过去行为对当前隐式评分的影响。
     *
     * @param rating
     */
    @Override
    public void applyTimeDecay(Rating rating) {
        Double oldRating = rating.getRating();
        LocalDateTime currentTime = LocalDateTime.now();
        LocalDateTime lastUpdate = rating.getUpdateTime();
        if (lastUpdate != null) {
            // 计算天数差
            double daysElapsed = ChronoUnit.DAYS.between(lastUpdate, currentTime);

            // 应用指数衰减
            double decayFactor = Math.exp(-TIME_DECAY_FACTOR * daysElapsed);
            rating.setRating(oldRating * decayFactor);

            log.info("评分衰减 -> user-item: {}-{}, 上次跟新时间：{}, 时间间隔：{}天，旧分数：{}, 新分数：{}",
                    rating.getUserId(), rating.getItemId(), lastUpdate, daysElapsed, oldRating, rating.getRating());
        }
    }
}
